/**
 *\*\file log.c
 *\*\author Nations
 *\*\version v1.0.0
 *\*\copyright Copyright (c) 2019, Nations Technologies Inc. All rights reserved.
 **/

#include "stdio.h"
#include "stdlib.h"
#include "data_recive_chain_v3.h"
#include "string.h"
#include <rtthread.h>

static int Data_chain_init(data_chain_handler_t *root, void *(*mem_alloc)(unsigned int))
{
    if (root == NULL)
        return -1;
    root->chain_root = NULL;
    // 计算节点数量
    root->max_cache_length = (root->max_cache_length > 0) ? root->max_cache_length : Data_max_cache_size;
    unsigned int length = root->max_cache_length;
    unsigned int node_num = length / Data_Node_Cache_size;
    if ((length % Data_Node_Cache_size) != 0)
        node_num++;
    root->max_data_node = node_num;

    root->data_root = mem_alloc(node_num * sizeof(data_node_t));
    if (root->data_root == NULL)
        return -2;
    // 节点初始化
    for (int i = 0; i < node_num - 1; i++)
    {
        root->data_root[i].length = 0;
        root->data_root[i].next = &(root->data_root[i + 1]);
    }
    // 防止溢出
    root->data_root[node_num - 1].length = 0;
    root->data_root[node_num - 1].next = NULL;

    root->data_lib = root->data_root;
    // 帧节点
    root->max_chain_node = (root->max_chain_node > 0) ? root->max_chain_node : Data_chain_node_size;
    node_num = root->max_chain_node;
    root->chain_root = mem_alloc(node_num * sizeof(data_node_t));
    if (root->chain_root == NULL)
        return -3;
    // 数据帧节点初始化
    for (int i = 0; i < node_num - 1; i++)
    {
        root->chain_root[i].startNode = NULL;
        root->chain_root[i].endNode = NULL;
        root->chain_root[i].total_datalength = 0;
        root->chain_root[i].next = &root->chain_root[i + 1];
    }
    // 防止溢出
    root->chain_root[node_num - 1].startNode = NULL;
    root->chain_root[node_num - 1].endNode = NULL;
    root->chain_root[node_num - 1].total_datalength = 0;
    root->chain_root[node_num - 1].next = NULL;
    root->chain_lib = root->chain_root;
    root->chain_start = NULL;
    root->chain_tail = NULL;
    return 0;
}
static chain_node_t *Data_chain_apply_new_chain_node(data_chain_handler_t *root)
{
    if (root == NULL)
        return NULL;
    if (root->chain_root == NULL)
        return NULL;
    if (root->chain_lib == NULL)
        return NULL;
		rt_enter_critical();
    chain_node_t *p = root->chain_lib;
    root->chain_lib = root->chain_lib->next;
    p->next = NULL;
    p->startNode = NULL;
    p->endNode = NULL;
    p->total_datalength = 0;
		rt_exit_critical();
    return p;
}
static data_node_t *Data_chain_apply_new_data_node(data_chain_handler_t *root)
{
    if (root == NULL)
        return NULL;
    if (root->data_root == NULL)
        return NULL;
    if (root->data_lib == NULL)
        return NULL;
		rt_enter_critical();
    data_node_t *p = root->data_lib;
    root->data_lib = root->data_lib->next;
    p->length = 0;
    p->next = NULL;
		rt_exit_critical();
    return p;
}
static int Data_chain_free_data_node(data_chain_handler_t *root, data_node_t *node)
{
    if (root == NULL)
        return -1;
    if (root->data_root == NULL)
        return -2;
    if (node > &(root->data_root[(root->max_data_node) - 1]) || node < (root->data_root))
        return -3;
		rt_enter_critical();
    node->next = root->data_lib;
    root->data_lib = node;
    node->length = 0;
		rt_exit_critical();
    return 0;
}
static int Data_chain_free_chain_node(data_chain_handler_t *root, chain_node_t *node)
{
    if (root == NULL)
        return -1;
    if (root->chain_root == NULL)
        return -2;
    if (node > &(root->chain_root[(root->max_chain_node) - 1]) || node < (root->chain_root))
        return -3;
		rt_enter_critical();
    node->next = root->chain_lib;
    root->chain_lib = node;
    data_node_t *q = NULL, *p = node->startNode;
    node->total_datalength = 0;
    node->startNode = NULL;
    node->endNode = NULL;
    for (; p != NULL;)
    {
        if (p > &(root->data_root[(root->max_data_node) - 1]) || p < (root->data_root))
				{
					rt_exit_critical();
          return -4;
        // 拆解一个节点
				}
        q = p;
        p = p->next;
        // 将节点入库，释放节点
        q->next = root->data_lib;
        root->data_lib = q;
        q->length = 0;
    }
		rt_exit_critical();
    return 0;
}

static int Data_chain_insert_new_chain_node(data_chain_handler_t *root, chain_node_t **chain_root, chain_node_t *chain_new, _chain_insert_type_t type)
{
    chain_node_t **start, **end;

    if (chain_new == NULL)
        return -3;
		rt_enter_critical();
    if (chain_root == NULL)
    {
        if (root == NULL)
				{
					rt_exit_critical();
            return -1;
				}
        start = &(root->chain_start);
        end = &(root->chain_tail);
    }
    else
    {
        if (*chain_root == NULL)
				{
					rt_exit_critical();
            return -2;
				}
        start = chain_root;
        for (*end = *start; *end != NULL && (*end)->next != NULL; (*end) = (*end)->next)
            ;
    }

    if (*start == NULL && *end == NULL)
    {
        *start = chain_new;
        *end = chain_new;
        chain_new->next = NULL;
			rt_exit_critical();
        return 0;
    }

    switch (type)
    {
    case CHAIN_TO_ROOT:
        chain_new->next = *start;
        *start = chain_new;
        break;
    case CHAIN_TO_TIL:
        (*end)->next = chain_new;
        chain_new->next = NULL;
        *end = chain_new;
        break;
    default:
			rt_exit_critical();
        return -4;
    }
		rt_exit_critical();
    return 0;
}
static int Data_chain_insert_new_data_node(chain_node_t *chain, data_node_t *data, int length)
{
    if (chain == NULL)
        return -1;
    if (data == NULL)
        return -2;
		rt_enter_critical();
    data->length = length;

    if (chain->startNode == NULL && chain->endNode == NULL)
    {
        chain->startNode = data;
        chain->endNode = data;
        chain->total_datalength = data->length;
    }
    else
    {
        chain->endNode->next = data;
        chain->endNode = data;
        chain->total_datalength += data->length;
    }
    data->next = NULL;
		rt_exit_critical();
    return 0;
}

static int Data_chain_get_chain_node_length(chain_node_t *chain)
{
    if (chain == NULL)
        return -1;
    return chain->total_datalength;
}
static chain_node_t *Data_chain_peek_chain_node(data_chain_handler_t *root, chain_node_t *chain_root)
{
    if (chain_root == NULL)
    {
        if (root == NULL)
            return NULL;
        return root->chain_start;
    }
    return chain_root;
}

static chain_node_t *Data_chain_pop_chain_node(data_chain_handler_t *root, chain_node_t **chain_root)
{
    chain_node_t *p = NULL;
	rt_enter_critical();
    if (chain_root == NULL)
    {
        if (root == NULL)
				{
					rt_exit_critical();
            return NULL;
				}
        if (root->chain_start != NULL)
        {
            p = root->chain_start;
            root->chain_start = root->chain_start->next;
            if (root->chain_start == NULL)
                root->chain_tail = NULL;
        }
				rt_exit_critical();
        return p;
    }
    p = *chain_root;
    *chain_root = (*chain_root)->next;
		rt_exit_critical();
    return p;
}

int Data_chain_recive_data_from_chain_node(chain_node_t *chain_root, unsigned char *buf, int length)
{
    int cnt = 0;
    if (chain_root == NULL)
        return -1;
    if (buf == NULL)
        return -2;
		rt_enter_critical();
    for (data_node_t *p = chain_root->startNode; p != NULL; p = p->next)
    {
        if (p->length < length)
        {
            memcpy(&buf[cnt], p->cache, p->length);
            cnt += p->length;
        }
        else
        {
            memcpy(buf, p->cache, length);
            cnt += length;
            break;
        }
    }
		rt_exit_critical();
    return cnt;
}

const chain_node_func_t Chain_func = {
    .apply_new_chain_node = Data_chain_apply_new_chain_node,
    .apply_new_data_node = Data_chain_apply_new_data_node,
    .free_chain_node = Data_chain_free_chain_node,
    .free_data_node = Data_chain_free_data_node,
    .get_chain_node_length = Data_chain_get_chain_node_length,
    .init = Data_chain_init,
    .insert_new_chain_node = Data_chain_insert_new_chain_node,
    .insert_new_data_node = Data_chain_insert_new_data_node,
    .peek_chain_node = Data_chain_peek_chain_node,
    .pop_chain_node = Data_chain_pop_chain_node,
    .recive_data_from_chain_node = Data_chain_recive_data_from_chain_node,
};
